package com.yanqu.road.server.channelserver.manager.scene;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.enums.eSceneType;
import com.yanqu.road.entity.scene.UserScene;
import com.yanqu.road.logic.pb.ScenePb;
import com.yanqu.road.pb.scene.SceneProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.YanQuMessageUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 跨服场景
 * desc
 * 1. initActivity 把活动信息放进去，找不到或过期时，移除旧数据
 * 2. PERMANENT_ACTIVITY_ID 常驻系统用这个作为活动ID
 */
public class ChannelSceneMgr {

    // 常驻系统用的活动ID
    private static final int PERMANENT_ACTIVITY_ID = -1;

    // 日志
    private static Logger logger = LogManager.getLogger(ChannelSceneMgr.class.getName());

    // 场景锁
    private static final Object lockObject = new Object();

    // 活动信息          Map<活动ID，活动数据>
    private static Map<Integer, ActivityInfo> activityInfoMap = new ConcurrentHashMap<>();
    // 玩家              Map<用户ID，用户所在场景>
    private static Map<Long, UserScene> userMap = new ConcurrentHashMap<>();
    // 场景              Map<活动ID，类型，房间号，用户ID，用户所在场景>
    private static Map<Integer, Map<Integer, Map<String, Map<Long, UserScene>>>> sceneMap = new ConcurrentHashMap<>();

    // 同步操作锁
    private static final Object lockActionObject = new Object();
    // 待同步操作        Map<活动ID，待同步数据>
    private static Map<Integer, List<SceneProto.SceneActionMsg>> actionMap = new ConcurrentHashMap<>();

    /**
     * 初始化活动
     */
    public static void initActivity(ActivityInfo info) {
        if (info != null) {
            activityInfoMap.put(info.getActivityId(), info);
        }
    }

    /**
     * 进入场景
     */
    public static boolean enterScene(UserScene userScene, boolean syncGame) {
        synchronized (lockObject) {
            // 能否操作
            UserScene oldScene = userMap.get(userScene.getUserId());
            if (oldScene != null && oldScene.getUpdateTime() >= userScene.getUpdateTime()) {
                return false;
            }
            // 退出旧场景
            if (oldScene != null) {
                userMap.remove(oldScene.getUserId());
                if (sceneMap.containsKey(oldScene.getActivityId()) &&
                        sceneMap.get(oldScene.getActivityId()).containsKey(oldScene.getSceneType()) &&
                        sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).containsKey(oldScene.getSceneId())) {
                    sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).get(oldScene.getSceneId()).remove(oldScene.getUserId());
                }
            }
            // 初始化新场景
            if (!sceneMap.containsKey(userScene.getActivityId())) {
                sceneMap.put(userScene.getActivityId(), new ConcurrentHashMap<>());
            }
            if (!sceneMap.get(userScene.getActivityId()).containsKey(userScene.getSceneType())) {
                sceneMap.get(userScene.getActivityId()).put(userScene.getSceneType(), new ConcurrentHashMap<>());
            }
            if (!sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).containsKey(userScene.getSceneId())) {
                sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).put(userScene.getSceneId(), new ConcurrentHashMap<>());
            }
            // 加入新场景
            userMap.put(userScene.getUserId(), userScene);
            sceneMap.get(userScene.getActivityId()).get(userScene.getSceneType()).get(userScene.getSceneId()).put(userScene.getUserId(), userScene);
            // 同步游戏服
            if (syncGame) {
                gameSceneUpdate(userScene, 1);
            }
            return true;
        }
    }

    /**
     * 退出场景
     */
    public static boolean quitScene(long userId, long updateTime) {
        synchronized (lockObject) {
            // 能否操作
            UserScene oldScene = userMap.get(userId);
            if (oldScene != null && oldScene.getUpdateTime() >= updateTime) {
                return false;
            }
            // 退出旧场景
            if (oldScene != null) {
                userMap.remove(oldScene.getUserId());
                if (sceneMap.containsKey(oldScene.getActivityId()) &&
                        sceneMap.get(oldScene.getActivityId()).containsKey(oldScene.getSceneType()) &&
                        sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).containsKey(oldScene.getSceneId())) {
                    sceneMap.get(oldScene.getActivityId()).get(oldScene.getSceneType()).get(oldScene.getSceneId()).remove(oldScene.getUserId());
                }
            }
            return true;
        }
    }

    /**
     * 获取场景内玩家
     */
    public static List<UserScene> getSceneUserList(int activityId, int sceneType, String sceneId, int maxCount) {
        List<UserScene> userSceneList = new ArrayList<>();
        Map<Integer, Map<String, Map<Long, UserScene>>> map1 = sceneMap.get(activityId);
        if (map1 == null) return userSceneList;
        Map<String, Map<Long, UserScene>> map2 = map1.get(sceneType);
        if (map2 == null) return userSceneList;
        Map<Long, UserScene> map3 = map2.get(sceneId);
        if (map3 == null) return userSceneList;

        userSceneList = map3.values().stream().sorted(Comparator.comparing(UserScene::getUpdateTime)).collect(Collectors.toList());
        if (userSceneList.size() > maxCount) {
            userSceneList = userSceneList.subList(userSceneList.size() - maxCount, userSceneList.size());
        }
        return userSceneList;
    }

    /**
     * 获取玩家所在场景
     */
    public static UserScene getUserScene(long userId) {
        return userMap.get(userId);
    }

    /**
     * 清空场景玩家，不带同步
     */
    public static void removeScene(int activityId, eSceneType sceneType, String sceneId) {
        synchronized (lockObject) {
            Map<Integer, Map<String, Map<Long, UserScene>>> mapMap = sceneMap.get(activityId);
            if (mapMap == null) {
                return;
            }

            Map<String, Map<Long, UserScene>> map = mapMap.get(sceneType.getValue());
            if (map == null) {
                return;
            }

            Map<Long, UserScene> sceneMap = map.get(sceneId);
            if (sceneMap == null) {
                return;
            }

            // 清空
            map.remove(sceneId);
            for (Long userId : sceneMap.keySet()) {
                userMap.remove(userId);
            }
        }
    }

    /**
     * 添加玩家操作
     */
    public static void addAction(int activityId, SceneProto.SceneActionMsg actionMsg) {
        synchronized (lockActionObject) {
            if (!actionMap.containsKey(activityId)) {
                actionMap.put(activityId, new ArrayList<>());
            }
            actionMap.get(activityId).add(actionMsg);
        }
    }

    /**
     * 同步玩家操作
     */
    public static void syncAction() {
        Map<Integer, List<SceneProto.SceneActionMsg>> tmpMap = new ConcurrentHashMap<>(actionMap);
        synchronized (lockActionObject) {
            actionMap.clear();
        }
        // 同步到各个区服
        for (Map.Entry<Integer, List<SceneProto.SceneActionMsg>> entry : tmpMap.entrySet()) {
            List<SceneProto.SceneActionMsg> actionMsgList = entry.getValue();
            if (actionMsgList.isEmpty()) continue;
            int activityId = entry.getKey();
            ActivityInfo activityInfo = activityInfoMap.get(activityId);
            if (activityInfo == null) continue;
            // 同步
            SceneProto.SyncSceneActionRespMsg.Builder builder = SceneProto.SyncSceneActionRespMsg.newBuilder();
            builder.setActivityId(activityId);
            builder.addAllActionList(actionMsgList);
            for (long serverId : activityInfo.getServerIdList()) {
                MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_CROSS_SCENE_ACTION_SYNC, builder));
            }
        }
    }

    /**
     * 通知游戏服刷新场景状态
     *
     * @param type 1进入，2退出
     */
    public static void gameSceneUpdate(UserScene userScene, int type) {
        SceneProto.UpdateSceneFromCrossReqMsg.Builder sceneBuilder = SceneProto.UpdateSceneFromCrossReqMsg.newBuilder();
        sceneBuilder.setSceneMsg(ScenePb.parseSceneMsg(userScene));
        sceneBuilder.setType(type);
        MessageHelper.sendPacket(userScene.getPlayerSceneInfo().getServerId(), userScene.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_CROSS_SCENE_UPDATE, sceneBuilder));
    }

    /**
     * 清理旧数据
     */
    public static void cleanOldData() {
        synchronized (lockObject) {
            long now = System.currentTimeMillis() / 1000;
            for (Map.Entry<Integer, Map<Integer, Map<String, Map<Long, UserScene>>>> activityEntry : sceneMap.entrySet()) {
                if (activityEntry.getKey() == PERMANENT_ACTIVITY_ID) {
                    continue;
                }
                ActivityInfo info = activityInfoMap.get(activityEntry.getKey());
                if (info == null || info.getEndShowTime() < now) {
                    sceneMap.remove(activityEntry.getKey());
                    activityInfoMap.remove(activityEntry.getKey());
                }
            }
        }
    }
}
